//
//  KLMMesh.swift
//  KLM
//
//  Created by 朱雨 on 2021/11/5.
//

import Foundation
import nRFMeshProvision

class KLMMesh {
    
    ///在线设备的UUID - 记录在线设备数据
    var onLineNodes: Set<String> = []
    
    //单例
    static let instacnce = KLMMesh()
    private init(){}
    
    static func createMesh(name: String) -> String {
        
        let provisioner = Provisioner(name: UIDevice.current.name,
                                      allocatedUnicastRange: [AddressRange(0x0001...0x7FFF)],
                                      allocatedGroupRange:   [AddressRange(0xC000...0xCC9A)],
                                      allocatedSceneRange:   [SceneRange(0x0001...0x3333)])
        //创建一个APP key
        let network = MeshNetworkManager().createNewMeshNetwork(withName: name, by: provisioner)
        let newKey: Data! = Data.random128BitKey()
        do {
            try network.add(applicationKey: newKey, withIndex: 0, name: "new key")
        } catch  {
            print(error)
        }
        ///配置数据转化成data
        let encoder = JSONEncoder()
        encoder.dateEncodingStrategy = .iso8601
        let data = try! encoder.encode(network)
        ///data转化成字符串
        let newStr = String(data: data, encoding: .utf8)
        return newStr!
        
    }
    ///获取存储的家庭
    static func loadHome() -> KLMHomeModel? {
        return KLMCache.getCache(KLMHomeModel.self, key: "home")
        
    }
    ///保存选择的家庭
    static func saveHome(home: KLMHomeModel?) {
        KLMCache.setCache(model: home, key: "home")
        KLMCache.setCache(model: home, key: "home\(home!.id)")
    }
    ///删除存储的家庭 针对当前存储的家庭
    static func removeHome() {
        KLMCache.removeObject(key: "home")
    }
    ///删除存储的家庭 包括缓存的家庭
    static func deleteHome() {
        if let home = KLMMesh.loadHome() {
            KLMCache.removeObject(key: "home\(home.id)")
        }
        KLMMesh.removeHome()
    }
    ///根据meshid获取本地保存的数据
    static func getHome(homeId: Int) -> KLMHomeModel? {
        return KLMCache.getCache(KLMHomeModel.self, key: "home\(homeId)")
    }
    
    static func saveGroup(_ group: KLMGroup) {
        KLMCache.setCache(model: group, key: "KLMGroupNew")
    }
    
    static func loadGroup() -> KLMGroup? {
        return KLMCache.getCache(KLMGroup.self, key: "KLMGroupNew")
    }
    ///删除缓存分组
    static func removeGroup() {
        KLMCache.removeObject(key: "KLMGroupNew")
    }
    
    ///mesh数据写入本地 - 同时重新蓝牙连接
    static func loadHomeMeshDataAndReload(meshConfiguration: String) {
        
        loadHomeMeshData(meshConfiguration: meshConfiguration)
        reload()
        getProvisionerAddressFromServer()
    }
    
    ///mesh数据写入本地 - 仅保存
    static func loadHomeMeshData(meshConfiguration: String) {
        
        ///测试导入
        let manager = MeshNetworkManager.instance
        do {
            let data = meshConfiguration.data(using: .utf8)
            _ = try manager.import(from: data!)
            if manager.save() {
                
            }
        } catch {
            print(error)
        }
    }
    
    private static func reload() {
        
        DispatchQueue.main.async {
            (UIApplication.shared.delegate as! AppDelegate).meshNetworkDidChange()
            
        }
    }
    ///从服务器获取单播地址
    private static func getProvisionerAddressFromServer() {
        
        //从服务器获取地址
        let model = KLMMesh.loadHome()!
        KLMService.getMeshProvisonerAddress(meshId: model.id, uuid: KLMTool.getAppUUID()) { response in
            guard var address = response as? Int else { return }
            
            let manager = MeshNetworkManager.instance
            let meshNetwork = manager.meshNetwork!
            let provisioner: Provisioner =  (meshNetwork.provisioners.first)!
            address = Int(provisioner.allocatedUnicastRange.first!.highAddress) - address
            let newAddress: Address = Address.init(address)
            
            changeProvisonerAddress(newAddress: newAddress)

        } failure: { error in
            
            ///如果是token失效，不需要提示
            if error.code == 401 {
                return
            }
            
            let message: String = error.userInfo["error"] as! String            
            KLMAlertController.showAlertWithTitle(title: KLMLocalizable.LANGLOC("Failed to get the address from the server. Please make sure the network is normal and then refresh the page"), message: message)
            
        }
    }
    ///更改provisoner的 unicastAddress
    private static func changeProvisonerAddress(newAddress: Address) {
        
        let manager = MeshNetworkManager.instance
        let meshNetwork = manager.meshNetwork!
        let provisioner: Provisioner =  (meshNetwork.provisioners.first)!
        if let node = provisioner.node {
            let unicastAddresses = node.elements.map { $0.unicastAddress }
            manager.proxyFilter?.remove(addresses: unicastAddresses)
        }
        do {
            try meshNetwork.assign(unicastAddress: newAddress, for: provisioner)
            // Add the new addresses to the Proxy Filter.
            let unicastAddresses = provisioner.node!.elements.map { $0.unicastAddress }
            manager.proxyFilter?.add(addresses: unicastAddresses)
        } catch  {
            print(error)
        }
        
        if manager.save() {
            
        }
    }
    ///从服务器获取配置数据，加载到本地
    static func getMeshData(success: @escaping () -> Void, failure: @escaping KLMResponseFailure) {
        let meshId = KLMMesh.loadHome()?.id
        KLMService.getMeshInfo(id: meshId!) { response in
            let model = response as? KLMHomeModel
            ///存储当前家庭
            KLMMesh.saveHome(home: model)
            ///存储mesh数据 - 会改变Provisioner的单播地址，想个办法，不要更改单播地址
            let provisionerAddress = MeshNetworkManager.instance.meshNetwork?.localProvisioner?.unicastAddress
            KLMLog("当前Provisioner的单播地址 = \(String(describing: provisionerAddress))")
            KLMMesh.loadHomeMeshData(meshConfiguration: model!.meshConfiguration)
            ///要改单播地址 - 泥马的，要了我老命
            changeProvisonerAddress(newAddress: provisionerAddress!)
            success()
        } failure: { error in
            failure(error)
        }
    }
}

extension KLMMesh {
    
    ///将配置数据字符串转化成模型数据
    static func getMeshNetwork(meshConfiguration: String) -> MeshNetwork {
        
        let data = meshConfiguration.data(using: String.Encoding.utf8)!
        let decoder = JSONDecoder()
        decoder.dateDecodingStrategy = .iso8601
        let meshNetwork = try! decoder.decode(MeshNetwork.self, from: data)
        return meshNetwork
    }
}

extension KLMMesh {
    //退出登录
    static func logout() {
        
        ///token清空
        KLMSetUserDefault("token", nil)
        ///清空家庭数据
        removeHome()
        ///清空用户数据
        KLMUser.removeUserInfo()
        ///清空分组数据
        removeGroup()
    }
    ///是否有家庭
    static func isLoadMesh() -> Bool {
        
        return KLMMesh.loadHome() == nil ? false : true
    }
        
    ///是否可以修改mesh配置数据
    static func canEditMesh(success: @escaping ()->(), failure: @escaping ()->()) {
        
        if isLoadMesh() == false {
            SVProgressHUD.showInfo(withStatus: KLMLocalizable.LANGLOC("Please go to About > Store Management create a store"))
            failure()
            return
        }
        
        SVProgressHUD.show()
        KLMService.ping { response in
            SVProgressHUD.dismiss()
            if let data: KLMMeshUserData = response as? KLMMeshUserData {
                if data.userRoleType == .admin || data.userRoleType == .Owner {
                    success()
                    return
                }
            }
            SVProgressHUD.showInfo(withStatus: KLMLocalizable.LANGLOC("No permission"))
            failure()
        } failure: { error in
            SVProgressHUD.dismiss()
            KLMAlertController.showAlertWithTitle(title: nil, message: KLMLocalizable.LANGLOC("Network is unavailable,please check the network"))
            failure()
        }
    }
}
